/*
 * Copyright 2013-2019 Xia Jun(3979434@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************************************
 *                                                                                     *
 *                        Website : http://www.farsunset.com                           *
 *                                                                                     *
 ***************************************************************************************
 */
package com.workcell.workdata.im.mvc.controller.webrtc;

import com.workcell.workdata.im.annotation.ClientOrigin;
import com.workcell.workdata.im.annotation.CreateAction;
import com.workcell.workdata.im.annotation.UID;
import com.workcell.workdata.im.component.cim.pusher.WebrtcMessagePusher;
import com.workcell.workdata.im.component.redis.WebrtcGroupRedisTemplate;
import com.workcell.workdata.im.constant.MessageAction;
import com.workcell.workdata.im.entity.EventMessage;
import com.workcell.workdata.im.entity.Message;
import com.workcell.workdata.im.model.app.Origin;
import com.workcell.workdata.im.model.dto.TagMessage;
import com.workcell.workdata.im.model.request.*;
import com.workcell.workdata.im.model.response.ResponseEntity;
import com.workcell.workdata.im.util.JSON;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.LinkedList;

@RestController
@RequestMapping("/webrtc/group")
@Api(produces = "application/json", tags = "多人通话事件推送接口")
@Valid
public class WebrtcGroupController {

    @Resource
    private WebrtcMessagePusher webrtcMessagePusher;

    @Resource
    private WebrtcGroupRedisTemplate webrtcGroupRedisTemplate;


    @ApiOperation(httpMethod = "POST", value = "发起语音通话")
    @PostMapping(value = "/voice")
    @Validated(CreateAction.class)
    public ResponseEntity<Long> voice(@ApiIgnore @UID Long uid,
                                      @Valid @RequestBody CreateRoomRequest request) {

        Message message = new EventMessage();
        message.setSender(uid);
        message.setAction(MessageAction.ACTION_910);
        message.setContent(JSON.toJSONString(request.getMember()));
        message.setExtra(request.getTag());

        request.getMember().remove(uid);

        webrtcMessagePusher.push(message, new LinkedList<>(request.getMember().keySet()));

        return ResponseEntity.ok(System.currentTimeMillis());
    }

    @ApiOperation(httpMethod = "POST", value = "发起视频通话")
    @PostMapping(value = "/video")
    @Validated(CreateAction.class)
    public ResponseEntity<Long> video(@ApiIgnore @UID Long uid,
                                      @Valid @RequestBody CreateRoomRequest request) {

        Message message = new EventMessage();
        message.setSender(uid);
        message.setAction(MessageAction.ACTION_911);
        message.setContent(JSON.toJSONString(request.getMember()));
        message.setExtra(request.getTag());
        request.getMember().remove(uid);

        webrtcMessagePusher.push(message, new LinkedList<>(request.getMember().keySet()));

        return ResponseEntity.ok(System.currentTimeMillis());
    }

    @ApiOperation(httpMethod = "POST", value = "同意接听")
    @PostMapping(value = "/accept")
    @Validated(CreateAction.class)
    public ResponseEntity<Void> accept(@ApiIgnore @UID Long uid,
                                       @ApiIgnore @ClientOrigin Origin origin,
                                       @Valid @RequestBody RoomAcceptRequest request) {

        String tag = request.getTag();

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_912);
        message.setSender(uid);
        message.setExtra(tag);

        request.setTag(null);
        message.setContent(JSON.toJSONString(request));

        webrtcGroupRedisTemplate.cleanAll(tag, uid);

        webrtcMessagePusher.push(uid, message, origin);

        return ResponseEntity.ok();
    }


    @ApiOperation(httpMethod = "POST", value = "拒绝接听")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/reject")
    public ResponseEntity<Void> reject(@ApiIgnore @UID Long uid,
                                       @ApiIgnore @ClientOrigin Origin origin,
                                       @RequestParam String tag) {

        /*
         *记录用户拒绝加入会议
         */
        webrtcGroupRedisTemplate.markRejected(tag, uid);

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_913);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);

        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "忙线中")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/busy")
    public ResponseEntity<Void> busy(@ApiIgnore @UID Long uid,
                                     @ApiIgnore @ClientOrigin Origin origin,
                                     @RequestParam String tag) {

        /*
         *记录用户正忙无法加入会议
         */
        webrtcGroupRedisTemplate.markBusy(tag, uid);

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_914);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);


        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "麦克风开关")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "value", value = "开(true)/关(false)", paramType = "query", dataTypeClass = String.class)
    })
    @PostMapping(value = "/microphone/switch")
    public ResponseEntity<Void> switchMicrophone(@ApiIgnore @UID Long uid,
                                                 @ApiIgnore @ClientOrigin Origin origin,
                                                 @RequestParam String tag,
                                                 @RequestParam boolean value) {

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_915);
        message.setSender(uid);
        message.setContent(String.valueOf(value));
        message.setExtra(tag);

        webrtcMessagePusher.push(uid,message,origin);

        return ResponseEntity.ok();
    }


    @ApiOperation(httpMethod = "POST", value = "摄像头开关")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "value", value = "开(true)/关(false)", paramType = "query", dataTypeClass = String.class)
    })
    @PostMapping(value = "/camera/switch")
    @Validated(CreateAction.class)
    public ResponseEntity<Void> switchCamera(@ApiIgnore @UID Long uid,
                                             @ApiIgnore @ClientOrigin Origin origin,
                                             @RequestParam String tag,
                                             @RequestParam boolean value) {

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_916);
        message.setSender(uid);
        message.setContent(String.valueOf(value));
        message.setExtra(tag);

        webrtcMessagePusher.push(uid,message,origin);

        return ResponseEntity.ok();
    }


    @ApiOperation(httpMethod = "POST", value = "语音通话添加成员")
    @PostMapping(value = "/add")
    @Validated(CreateAction.class)
    public ResponseEntity<Void> add(@ApiIgnore @UID Long uid,
                                    @ApiIgnore @ClientOrigin Origin origin,
                                    @Valid @RequestBody RoomAddRequest request) {


        /*
         * 向群里面用户发送消息 哪些人被加入了
         */

        TagMessage tagMessage = new TagMessage();
        tagMessage.setTag(request.getTag());
        tagMessage.setExtra(request.getTag());

        tagMessage.setAction(MessageAction.ACTION_917);
        tagMessage.setSender(uid);
        tagMessage.setContent(JSON.toJSONString(request.getNewMember()));
        
        webrtcMessagePusher.push(uid,tagMessage,origin);

        /*
         *  向新加入的人推送通话请求
         */
        Message message = new EventMessage();
        message.setSender(uid);
        message.setAction(request.isVideoMode() ? MessageAction.ACTION_911 : MessageAction.ACTION_910);
        message.setContent(JSON.toJSONString(request.getAllMember()));
        message.setExtra(request.getTag());

        webrtcMessagePusher.push(message, new LinkedList<>(request.getNewMember().keySet()));


        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "重新呼叫")
    @PostMapping(value = "/recall")
    @Validated(CreateAction.class)
    public ResponseEntity<Void> recall(@ApiIgnore @UID Long uid,
                                       @ApiIgnore @ClientOrigin Origin origin,
                                       @Valid @RequestBody RoomRecallRequest request) {

        webrtcGroupRedisTemplate.cleanAll(request.getTag(), request.getUid());

        /*
         * 向群里面用户发送消息
         */

        TagMessage tagMessage = new TagMessage();
        tagMessage.setTag(request.getTag());
        tagMessage.setExtra(request.getTag());

        tagMessage.setAction(MessageAction.ACTION_927);
        tagMessage.setSender(uid);
        tagMessage.setContent(String.valueOf(request.getUid()));

        webrtcMessagePusher.push(uid,tagMessage,origin);

        /*
         *  向新加入的人推送通话请求
         */
        Message message = new EventMessage();
        message.setSender(uid);
        message.setReceiver(request.getUid());
        message.setAction(request.isVideoMode() ? MessageAction.ACTION_911 : MessageAction.ACTION_910);
        message.setContent(JSON.toJSONString(request.getMember()));
        message.setExtra(request.getTag());

        webrtcMessagePusher.push(message, origin);

        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "退出通话")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/quit")
    public ResponseEntity<Void> quit(@ApiIgnore @UID Long uid,
                                     @ApiIgnore @ClientOrigin Origin origin,
                                     @RequestParam String tag) {

        /*
         *记录用户已经退出会议
         */
        webrtcGroupRedisTemplate.markQuited(tag, uid);

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_918);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);

        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "取消呼叫")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/cancel")
    public ResponseEntity<Void> cancel(@ApiIgnore @UID Long uid,
                                       @ApiIgnore @ClientOrigin Origin origin,
                                       @RequestParam String tag) {

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_919);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);

        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "发送offer")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "OK"),
            @ApiResponse(responseCode = "403", description = "对方已经拒绝加入会议"),
            @ApiResponse(responseCode = "404", description = "对方已经退出了会议"),
            @ApiResponse(responseCode = "423", description = "对方正在忙线中")
    })
    @PostMapping(value = "/transmit/offer")
    @Validated(CreateAction.class)
    public ResponseEntity<Void> offer(@ApiIgnore @UID Long uid,
                                      @ApiIgnore @ClientOrigin Origin origin,
                                      @Valid @RequestBody RoomOfferRequest request) {

        if (webrtcGroupRedisTemplate.isRejected(request.getTag(), request.getUid())) {
            return ResponseEntity.make(HttpStatus.FORBIDDEN, "对方已经拒绝加入会议");
        }

        if (webrtcGroupRedisTemplate.isQuited(request.getTag(), request.getUid())) {
            return ResponseEntity.make(HttpStatus.NOT_FOUND, "对方已经退出了会议");
        }

        if (webrtcGroupRedisTemplate.isBusy(request.getTag(), request.getUid())) {
            return ResponseEntity.make(HttpStatus.LOCKED, "对方正在忙线中");
        }

        Message message = new EventMessage();
        message.setAction(MessageAction.ACTION_920);
        message.setSender(uid);
        message.setContent(request.getDescription());
        message.setReceiver(request.getUid());
        message.setExtra(request.getMessageExtra());

        webrtcMessagePusher.push(message, origin);
        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "同步answer")
    @PostMapping(value = "/transmit/answer")
    @Validated(CreateAction.class)
    public ResponseEntity<Void> answer(@ApiIgnore @UID Long uid,
                                       @ApiIgnore @ClientOrigin Origin origin,
                                       @Valid @RequestBody RoomAnswerRequest request) {
        Message message = new EventMessage();
        message.setAction(MessageAction.ACTION_921);
        message.setSender(uid);
        message.setContent(request.getDescription());
        message.setReceiver(request.getUid());
        message.setExtra(request.getMessageExtra());

        webrtcMessagePusher.push(message, origin);
        return ResponseEntity.ok();
    }


    @ApiOperation(httpMethod = "POST", value = "同步IceCandidate")
    @PostMapping(value = "/transmit/ice")
    @Validated(CreateAction.class)
    public ResponseEntity<Void> ice(@ApiIgnore @UID Long uid,
                                    @ApiIgnore @ClientOrigin Origin origin,
                                    @Valid @RequestBody RoomIceRequest request) {

        Message message = new EventMessage();
        message.setAction(MessageAction.ACTION_922);
        message.setSender(uid);
        message.setContent(request.getContent());
        message.setReceiver(request.getUid());
        message.setExtra(request.getTag());

        webrtcMessagePusher.push(message, origin);

        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "未响应")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/timeout")
    public ResponseEntity<Void> timeout(@ApiIgnore @UID Long uid,
                                        @ApiIgnore @ClientOrigin Origin origin,
                                        @RequestParam String tag) {


        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_923);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);


        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "结束会议")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/finish")
    public ResponseEntity<Void> finish(@ApiIgnore @UID Long uid,
                                       @ApiIgnore @ClientOrigin Origin origin,
                                       @RequestParam String tag) {


        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_924);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);


        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "全员静音", notes = "关闭用户麦克风，且启用按钮置灰")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/microphone/disable")
    public ResponseEntity<Void> disableMicrophone(@ApiIgnore @UID Long uid,
                                                  @ApiIgnore @ClientOrigin Origin origin,
                                                  @RequestParam String tag) {

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_925);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);

        return ResponseEntity.ok();
    }

    @ApiOperation(httpMethod = "POST", value = "取消全员静音", notes = "用户可开启麦克风")
    @ApiImplicitParam(name = "tag", value = "房间号", paramType = "query", dataTypeClass = String.class)
    @PostMapping(value = "/microphone/resume")
    public ResponseEntity<Void> resumeMicrophone(@ApiIgnore @UID Long uid,
                                                 @ApiIgnore @ClientOrigin Origin origin,
                                                 @RequestParam String tag) {

        TagMessage message = new TagMessage();
        message.setTag(tag);
        message.setAction(MessageAction.ACTION_926);
        message.setSender(uid);
        message.setContent(tag);

        webrtcMessagePusher.push(uid,message,origin);

        return ResponseEntity.ok();
    }
}
